public with sharing class CreateIngenioAccountController {
    
    private Opportunity opp {get; set;}
    private ApexPages.StandardController controller {get; set;}
    
    public boolean ShowResult {get; set;}
    public boolean IsPostPay {get; set;}
    public string ErrorMessage {get; set;}
    public string PPCPageUrl {get; set;}
    
    public CreateIngenioAccountController (ApexPages.StandardController controller){
        this.controller = controller;               
        ID oppID = controller.getRecord().id;
        
        opp = [select ID, AccountID, Probability, Payment_Type__c from Opportunity where ID = :oppID];
                
        IsPostPay = opp.Payment_Type__c == 'Postpay';        
        
        ShowResult = false;
    }
    
    public PageReference CreateAccount(){
        ShowResult = true;
        ErrorMessage = null;
        PageReference pr = null;
        
        if(null == opp.Probability  || opp.Probability < 90){
            ErrorMessage = 'The opportunity probability must be at least 90%.';
            return null;         
        }
            
        if(!IsActiveAccount(opp.accountid)){
            ErrorMessage = 'The opportunity must be linked to a non-draft parent account.';
            return null;         
        }

        if(!HasContacts(opp.accountid)){
            ErrorMessage = 'The account linked to the opportunity must have at least one contact.';
            return null;         
        }

        try
        {        
            System.Assert(opp.accountid != null, 'Expected valid Account ID linked to the opportunity');
            ID ingenioAccountId = FindDraftIngenioAccount(opp);
            if(null == ingenioAccountId){
                Account ingenioAccount = CreateIngenioAccount(opp, opp.accountid);
                ingenioAccountId = ingenioAccount.id; 
            }
            
            if(!HasContacts(ingenioAccountId))
                CloneContact(opp.accountid, ingenioAccountId);
            

            pr = GetPPCUrl(ingenioAccountId, opp);
        }
        catch(Exception e){
            ErrorMessage = 'Error. Message: ' + e.GetMessage() + ' Cause: ' + e.GetCause() + ' Line Number: ' + e.GetLineNumber();
        }
        return pr;
    }
    
    private boolean IsActiveAccount(ID accountid){
        if(null == accountId)
            return false;
            
        Account a = [select Account_Status__c from account where id = :accountID];
        if(a.Account_Status__c == 'Active')
            return true;
    
        return false;
    }
    
    private PageReference GetPPCUrl(ID ingenioAccountID, Opportunity opp){
        AppEndPoints__c endpoints = AppEndPoints__c.getInstance();
        string url = 'http://' + endpoints.PayPerCallDomain__c + '/Registration/Registration.aspx';         
        PageReference ref = new PageReference(url);
        
        ref.getParameters().put('sfid', ingenioAccountID);
        
        if(IsPostPay){
            ref.getParameters().put('TID', 'MDY2QUFC');
        }
        
        return ref;
    }
   
    private ID FindDraftIngenioAccount(Opportunity opp){
        List<Account> a = [select ID from account where Opportunity__c = :opp.ID and Ingenio_UserID__c = null LIMIT 1];
        if(null != a && a.size() == 1)
            return a[0].ID;
        
        return null;
    }

    private Account CreateIngenioAccount(Opportunity opp, ID salesAccountID){
        Account a = new Account();
        a.RecordTypeID = RecordTypeHelper.GetRecordTypeIDByDevName('Account', 'National_Managed_Customer_Ingenio');
        a.ParentID = salesAccountID;
        a.Opportunity__c = opp.ID;
        
        List<Account> saList = [Select Name, OwnerID, Sales_Region__c, Office__c, Post_Sale_Manager__c, Corporate_City__c, Corporate_Country__c, Corporate_State_Province__c, Corporate_Street__c, Corporate_Zip_Code__c, Payment_Schedule__c, Payment_Method__c, Special_Instructions__c, Specify_Method_if_Other__C, Specify_Schedule_if_Other__c, BillingStreet, BillingCity, BillingState, BillingPostalCode, BillingCountry, Billing_Contact__c  from Account where ID = :salesAccountID];
        if(null == saList || saList.size() != 1)
            return null;
        
        Account sa = saList[0];

        a.Name = sa.Name;        
        a.OwnerID = sa.OwnerID;
        a.Sales_Region__c = sa.Sales_Region__c;
        a.Office__c = sa.Office__c;
        a.Post_Sale_Manager__c = sa.Post_Sale_Manager__c;
        a.Corporate_City__c = sa.Corporate_City__c;
        a.Corporate_Country__c = sa.Corporate_Country__c;
        a.Corporate_State_Province__c = sa.Corporate_State_Province__c;
        a.Corporate_Street__c = sa.Corporate_Street__c;
        a.Corporate_Zip_Code__c =sa.Corporate_Zip_Code__c;
        a.Payment_Schedule__c = sa.Payment_Schedule__c;
        a.Payment_Method__c= sa.Payment_Method__c;
        a.Special_Instructions__c = sa.Special_Instructions__c;
        a.Specify_Method_if_Other__C = sa.Specify_Method_if_Other__C;
        a.Specify_Schedule_if_Other__c = sa.Specify_Schedule_if_Other__c;
        a.BillingStreet = sa.BillingStreet;
        a.BillingCity = sa.BillingCity;
        a.BillingState = sa.BillingState;
        a.BillingPostalCode = sa.BillingPostalCode;
        a.BillingCountry = sa.BillingCountry;
        a.Billing_Contact__c = sa.Billing_Contact__c;
                
        insert a;
                
        return a;       
    }
 
    private boolean HasContacts(ID salesAccountId){
        List<Contact> contacts = [Select ID from Contact where AccountID = :salesAccountId LIMIT 1];
        return contacts.size() > 0;
    }
       
    private void CloneContact(ID salesAccountId, ID ingenioAccountID){
        Contact c = [Select ID, FirstName, LastName, Phone, Description, Ingenio_Domain__c, Ingenio_Member_Status__c, Email from Contact where AccountID = :salesAccountId LIMIT 1];
        Contact ingenioContact = c.clone(false, false);
        
        ingenioContact.AccountID = ingenioAccountID;
        ingenioContact.api_controlled__c = true;
        
        insert ingenioContact;
    }

}